﻿using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Common.Helper;
using DTcms.Core.DBFactory.Database;
using DTcms.Core.IServices;
using DTcms.Core.Model.Models;
using DTcms.Core.Model.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;

namespace DTcms.Core.Services
{
    /// <summary>
    /// 会员积分记录接口实现
    /// </summary>
    public class MemberPointLogService : BaseService, IMemberPointLogService
    {
        private readonly IMemberGroupService _memberGroupService;

        public MemberPointLogService(IDbContextFactory contentFactory,
            IMemberGroupService memberGroupService) : base(contentFactory)
        {
            _memberGroupService = memberGroupService;
        }

        /// <summary>
        /// 根据条件获取一条记录
        /// </summary>
        public async Task<MemberPointLogDto?> QueryAsync(Expression<Func<MemberPointLogDto, bool>> funcWhere,
            WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberPointLog>()
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberPointLogDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             Value = a.Value,
                             Remark = a.Remark,
                             AddTime = a.AddTime
                         });
            //加入查询条件并返回一条
            return await result.FirstOrDefaultAsync(funcWhere);
        }

        /// <summary>
        /// 根据条件获取列表
        /// </summary>
        public async Task<IEnumerable<MemberPointLogDto>> QueryListAsync(int top, Expression<Func<MemberPointLogDto, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberPointLog>()
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberPointLogDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             Value = a.Value,
                             Remark = a.Remark,
                             AddTime = a.AddTime
                         });
            result = result.Where(funcWhere);//加入查询条件
            result = LinqExtensions.OrderByBatch(result, orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 根据条件获取分页列表
        /// </summary>
        public async Task<PaginationList<MemberPointLogDto>> QueryPageAsync(int pageSize, int pageIndex,
            Expression<Func<MemberPointLogDto, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //联合查询重新组合
            var result = from a in _context.Set<MemberPointLog>()
                         from u in _context.Set<ApplicationUser>().Where(u => u.Id == a.UserId)
                         select (new MemberPointLogDto
                         {
                             Id = a.Id,
                             UserId = a.UserId,
                             UserName = u.UserName,
                             Value = a.Value,
                             Remark = a.Remark,
                             AddTime = a.AddTime
                         });
            result = result.Where(funcWhere);//加入查询条件
            result = LinqExtensions.OrderByBatch<MemberPointLogDto>(result, orderBy);//调用Linq扩展类排序
            return await PaginationList<MemberPointLogDto>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 新增一条数据，须检查是否正数，正数须同时增加会员积分及经验值，检查升级
        /// </summary>
        public async Task<MemberPointLog> AddAsync(MemberPointLog model, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var userModel = await _context.Set<Members>().FirstOrDefaultAsync(x => x.UserId == model.UserId);
            if (userModel == null)
            {
                throw new ResponseException("会员账户不存在或已删除", ErrorCode.NotFound, StatusCodes.Status404NotFound);
            }
            //如果是负数，检查会员积分是否够扣减
            if (model.Value < 0 && userModel.Point < (model.Value * -1))
            {
                throw new ResponseException("会员账户积分不足本次扣减");
            }
            userModel.Point += model.Value;//添加积分
            //如果是正数则增加经验值
            if (model.Value > 0)
            {
                userModel.Exp += model.Value;
                //查询当前会员组
                var currGroupModel = await _memberGroupService.QueryAsync(x => x.Id == userModel.GroupId);
                if (currGroupModel == null)
                {
                    throw new ResponseException("会员组不存在或已删除");
                }
                //检查有无可升级的会员组
                var upgradeGroupModel = await _memberGroupService.QueryAsync(x =>
                    x.Id != currGroupModel.Id
                    && x.IsUpgrade == 1
                    && x.MinExp >= currGroupModel.MaxExp
                    && x.MinExp <= userModel.Exp
                    && x.MaxExp >= userModel.Exp);
                if (upgradeGroupModel != null && upgradeGroupModel.Amount >= currGroupModel.Amount)
                {
                    userModel.GroupId = upgradeGroupModel.Id;
                }
            }
            //新增积分记录
            await _context.Set<MemberPointLog>().AddAsync(model);
            await this.SaveAsync();

            return model;
        }
    }
}
